package disk;

import java.util.ArrayList;

/**
 * 文件分配表类
 * 
 * @author vincent
 * 
 */
public class FAT {
	/**
	 * 0、1磁盘块用于FAT的保存
	 */
	private Block[] fatBlocks;

	/**
	 * 构造函数
	 * 
	 * @param blocks
	 */
	public FAT(Block[] blocks) {
		this.fatBlocks = blocks;
		// 第0、1盘块用于fat的保存
		fatBlocks[0].setByte(0, (byte) 255);
		fatBlocks[0].setByte(1, (byte) 255);

		// 第2盘块用于根目录的保存
		fatBlocks[0].setByte(2, (byte) 255);
	}

	/**
	 * 设置文件分配表第index字节的值
	 * 
	 * @param index
	 * @param value
	 */
	public void setByte(int index, byte value) {
		int i = index / 64;
		int j = index % 64;
		fatBlocks[i].setByte(j, value);
	}

	/**
	 * 获取文件分配表的值
	 * 
	 * @param index
	 * @param value
	 */
	public byte getByte(int index) {
		int i = index / 64;
		int j = index % 64;
		byte[] bytes = fatBlocks[i].getBytes();
		return bytes[j];
	}

	/**
	 * 获取fat盘块的数据
	 * 
	 * @param index
	 * @return
	 */
	public Block getFatBlock(int index) {
		return fatBlocks[index];
	}

	/**
	 * 获取一个空闲盘块的盘块号
	 * 
	 * @return
	 */
	public int getFreeBlockIndex() {
		// 第0、1、2块已被占用
		for (int i = 3; i < 128; i++) {
			if (this.getByte(i) == 0)
				return i;
		}
		return -1;
	}

	/**
	 * 分配磁盘块
	 * 
	 * @param num 分配的数量
	 * @return
	 */
	public byte[] allocateBlock(int num) {
		byte[] blockIndexes = new byte[num]; // 分配的盘块起始号
		byte hasAllocate = 0; // 已经分配的盘块数
		// 第0、1、2块已被占用 从前到后搜索可用盘块
		for (int index = 3; index < 128; index++) {
			// 判断是否空闲
			if (this.getByte(index) != 0) {
				continue;
			}
			// System.out.println("分配盘块" + index);
			// 判读是否分配够
			if (hasAllocate == num) {
				break;
			}
			// 把分配到的盘块号记录下来
			blockIndexes[hasAllocate++] = (byte) index;
		}
		// 判断是否有足够的盘块分给新的文件或目录
		if (hasAllocate != num) {
			return null;
		}
		int maxIndex = num - 1;
		for (int i = 0; i < maxIndex; i++) {
			this.setByte(blockIndexes[i], blockIndexes[i + 1]);
		}

		this.setByte(blockIndexes[num - 1], (byte) 255);
		return blockIndexes;
	}

	/**
	 * 获取一个文件所占用的盘块索引
	 * 
	 * @return
	 */
	public ArrayList<Byte> getFileAllocateList(int index) {
		ArrayList<Byte> list = new ArrayList<Byte>();
		while (getByte(index) != -1) {
			list.add((byte) index);
			index = getByte(index);
		}
		list.add((byte) index);
		return list;
	}

	/**
	 * 获取一个文件所占用的盘块索引
	 * 
	 * @return
	 */
	public void clearFileAllocateList(int index) {
		int lastIndex = -1;
		while (getByte(index) != -1) {
			lastIndex = index;
			index = getByte(index); // 移动到下一个盘块
			setByte(lastIndex, (byte) 0); // 标记为空闲块
		}
		setByte(index, (byte) 0);
	}

	/**
	 * 缩短文件分配链表
	 * 
	 * @param index
	 * @param newLength
	 */
	public void cutDownFileAllocateList(int index, int newLength) {
		int i = index + newLength - 1;
		setByte(i, (byte) 255);
		clearFileAllocateList(i + 1);
	}

	/**
	 * 扩增文件分配链表
	 * 
	 * @param index
	 * @param newLength
	 */
	public void appendFileAllocateList(int index1, int index2) {
		while (getByte(index1) != -1) {
			index1 = getByte(index1);
		}
		setByte((byte) index1, (byte) index2);
	}
}
